﻿Imports System.Net
Imports System.Net.NetworkInformation
Imports System.IO

Public Class frmASimpleNetworkMapper

    'Variables
    Dim strMyIP As String
    Dim intIndex As Integer = 0


    Dim ipaSendList() As IPAddress
    Dim ipaReplyList() As IPAddress
    Dim strLastUsedFilename As String


    Dim blnCancelledStatus As Boolean
    Dim ipqMySubNet As New IPDottedQuad
    Dim intCIDR As Integer

    'LOAD
    Private Sub frmASimpleNetworkMapper_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        'Set images' status
        imgDisconnected.Visible = True
        imgConnected.Visible = False
        lstActive.SelectionMode = SelectionMode.MultiExtended
        'Check network status and activate appropriate display icon and other conditionals
        CheckStatus()

        If My.Settings.AutoSave = True Then
            chkAutoSaveToLast.Checked = True
        Else
            chkAutoSaveToLast.Checked = False
        End If

        If My.Settings.ExitAfterSave = True Then
            chkExitAfterSave.Checked = True
            blnExitAfterSave = True
        Else
            chkExitAfterSave.Checked = False
            blnExitAfterSave = False
        End If

        'Set to start status
        btnCancel.Enabled = False
        btnCancel.Visible = True
        btnInitiateMapping.Visible = True
        btnInitiateMapping.Enabled = True
        barScanProgress.Visible = False
        blnExitAfterSave = False
        txtPingTimeout.Text = My.Settings.PingTimeout
        txtCIDR.Text = My.Settings.CIDR
        radCIDR.Checked = True

        'Populate the My IP Address combo box with IPv4 only
        loadMyIPs()

        'For debugging only
        Debug.Listeners.Add(New ConsoleTraceListener())

    End Sub
    'END LOAD

    'Cancel
    Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click
        blnCancelledStatus = True
        btnCancel.Enabled = False
        btnCancel.Visible = True
        btnInitiateMapping.Visible = True
        btnInitiateMapping.Enabled = True
    End Sub

    'Map the network
    Private Sub btnInitiateMapping_Click(sender As System.Object, e As System.EventArgs) Handles btnInitiateMapping.Click
        btnInitiateMapping.Visible = False
        btnInitiateMapping.Enabled = False
        btnCancel.Enabled = True
        btnCancel.Visible = True
        Dim m_blnStatus As Boolean
        Dim intTimeOutValue As Integer = My.Settings.PingTimeout
        Dim m_intlength As Integer
        Dim ipaReplyList() As IPAddress
        ReDim ipaReplyList(1)
        'Get own IP
        strMyIP = cmbMyIP.Text()
        ipaReplyList(0) = IPAddress.Parse(strMyIP)

        'Determine network address
        If radA.Checked = True Then
            intCIDR = 8
        ElseIf radB.Checked = True Then
            intCIDR = 16
        ElseIf radC.Checked = True Then
            intCIDR = 24
        Else
            intCIDR = txtCIDR.Text
        End If

        'Get our list of IPs based on our IP and CIDR and return as an array of IPAddress
        ipaSendList = EnumSendList(intCIDR, strMyIP)
        intTotalSendCount = ipaSendList.Length
        barScanProgress.Maximum = intTotalSendCount
        barScanProgress.Visible = True
        Me.lstActive.Items.Clear()
        Dim length As Integer
        If Integer.TryParse(txtPingTimeout.Text, intTimeOutValue) Then
            If intTimeOutValue > 0 And intTimeOutValue <= 20000 Then
                'Send pings
                ipaSendList(0) = Nothing
                For Each m_IP As IPAddress In ipaSendList
                    If m_IP IsNot Nothing Then
                        m_blnStatus = SendPing(m_IP, intTimeOutValue)

                        If m_blnStatus = True Then
                            m_intlength = ipaReplyList.Length
                            ReDim Preserve ipaReplyList(length)
                            ipaReplyList(length) = m_IP
                            Me.lstActive.Items.Add(m_IP.ToString)
                            barScanProgress.Increment(1)
                        End If
                    End If
                Next

                blnCancelledStatus = False
                btnInitiateMapping.Visible = True
                btnInitiateMapping.Enabled = True
                btnCancel.Enabled = False
                btnCancel.Visible = True
                barScanProgress.Visible = False
                barScanProgress.Value = 0

            Else
                MessageBox.Show("Timeout value must be a postive integer no greater than 20000", "Invalid Entry", MessageBoxButtons.OK)
            End If
        Else
            MessageBox.Show("Timeout value must be a postive integer no greater than 20000", "Invalid Entry", MessageBoxButtons.OK)
        End If
    End Sub


    'Standard Subs
    Private Sub btnExit_Click(sender As System.Object, e As System.EventArgs) Handles btnExit.Click
        'Close gracefully
        My.Settings.AutoSave = chkAutoSaveToLast.Checked
        My.Settings.ExitAfterSave = chkExitAfterSave.Checked
        My.Settings.PingTimeout = txtPingTimeout.Text
        My.Settings.CIDR = txtCIDR.Text
        Me.Close()
    End Sub

    Private Sub btnSaveFile_Click(sender As System.Object, e As System.EventArgs) Handles btnSaveFile.Click

        Dim saveFileDialog1 As New SaveFileDialog()
        Dim SaveFileName As String

        saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
        saveFileDialog1.FilterIndex = 1
        saveFileDialog1.RestoreDirectory = True
        saveFileDialog1.FileName = My.Settings.LastUsedFilename

        If saveFileDialog1.ShowDialog() = DialogResult.OK Then
            SaveFileName = CStr(saveFileDialog1.FileName)
            SaveFile(SaveFileName)
        End If
    End Sub

    'Custom Subs
    'Enumerate list of IPs to check.
    Private Function EnumSendList(ByVal v_intCIDR As Integer, ByVal v_strMyIP As String)
        Dim m_ipaTmp As IPAddress
        m_ipaTmp = IPAddress.Parse(v_strMyIP)
        Dim v_ipaPingList() As IPAddress
        ReDim v_ipaPingList(1)
        v_ipaPingList(0) = m_ipaTmp
        Dim m_idqNetwork As New IPDottedQuad

        Dim strDebug() As String
        ReDim strDebug(1)
        strDebug(0) = ""

        Dim m_intCountA As Integer = 0
        Dim m_intCountB As Integer = 0
        Dim m_intCountC As Integer = 0
        Dim m_intIPCount As Integer = 0
        Dim m_intlength As Integer = 0
        Dim i As Integer = 0
        Dim j As Integer = 0
        Dim k As Integer = 0
        Dim m As Integer = 0
        Dim m_intIPCountA As Integer = 0
        Dim m_intIPCountB As Integer = 0
        Dim m_intIPCountC As Integer = 0


        m_idqNetwork = GetNetworkAddress(v_intCIDR, v_strMyIP)
        m_intIPCount = (2 ^ (32 - v_intCIDR)) - 1

        'LARGEST
        If m_intIPCount > 16777215 Then
            m_intIPCountA = m_intIPCount / 16777216
            While m < m_intIPCountA
                m_idqNetwork.A = m
                m_idqNetwork.B = k
                m_idqNetwork.C = j
                m_idqNetwork.D = 0
                While k < m_intIPCountB
                    ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                    'ReDim Preserve strDebug(strDebug.Length)
                    'strDebug(strDebug.Length - 1) = "***IN j WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                    v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                    m_idqNetwork.B = k
                    m_idqNetwork.C = j
                    m_idqNetwork.D = 0
                    While j < m_intIPCountC
                        ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                        'ReDim Preserve strDebug(strDebug.Length)
                        'strDebug(strDebug.Length - 1) = "***IN j WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                        v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                        m_idqNetwork.C = j
                        m_idqNetwork.D = 0
                        While i < 255

                            'ReDim Preserve strDebug(strDebug.Length)
                            i += 1
                            'strDebug(strDebug.Length - 1) = "***IN i WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                            If i = 255 And j <> m_intIPCountC Then
                            Else
                                m_idqNetwork.D = i
                                If v_ipaPingList(v_ipaPingList.Length - 2) IsNot v_ipaPingList(v_ipaPingList.Length - 1) Then
                                    v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                                    ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                                Else
                                    ReDim Preserve v_ipaPingList(v_ipaPingList.Length - 3)
                                End If
                            End If
                        End While
                        i = 0
                        j += 1
                    End While
                    m_idqNetwork.C = 0
                    k += 1
                End While
                m_idqNetwork.B = 0
                m += 1
            End While

            'LARGER
            i = 0
            j = 0
            k = 0
            m_intlength = 0
        ElseIf m_intIPCount > 65535 Then
            m_intIPCountB = m_intIPCount / 65536
            While i < m_intIPCountB
                ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                'ReDim Preserve strDebug(strDebug.Length)
                'strDebug(strDebug.Length - 1) = "***IN j WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                m_idqNetwork.B = k
                m_idqNetwork.C = j
                m_idqNetwork.D = 0
                While j < m_intIPCountC
                    ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                    'ReDim Preserve strDebug(strDebug.Length)
                    'strDebug(strDebug.Length - 1) = "***IN j WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                    v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                    m_idqNetwork.C = j
                    m_idqNetwork.D = 0
                    While i < 255

                        'ReDim Preserve strDebug(strDebug.Length)
                        i += 1
                        'strDebug(strDebug.Length - 1) = "***IN i WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                        If i = 255 And j <> m_intIPCountC Then
                        Else
                            m_idqNetwork.D = i
                            If v_ipaPingList(v_ipaPingList.Length - 2) IsNot v_ipaPingList(v_ipaPingList.Length - 1) Then
                                v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                                ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                            Else
                                ReDim Preserve v_ipaPingList(v_ipaPingList.Length - 3)
                            End If
                        End If
                    End While
                    i = 0
                    j += 1
                End While
                m_idqNetwork.C = 0
                i += 1
            End While

            'Large
            i = 0
            j = 0

        ElseIf m_intIPCount > 255 Then
            m_intIPCountC = (m_intIPCount / 256) - 1
            While j <= m_intIPCountC
                ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                'ReDim Preserve strDebug(strDebug.Length)
                'strDebug(strDebug.Length - 1) = "***IN j WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                m_idqNetwork.C = j
                m_idqNetwork.D = 0
                While i < 255

                    'ReDim Preserve strDebug(strDebug.Length)
                    i += 1
                    'strDebug(strDebug.Length - 1) = "***IN i WHILE j= " & j & "  i= " & i & "  IP Address= " & m_idqNetwork.A & "." & m_idqNetwork.B & "." & m_idqNetwork.C & "." & m_idqNetwork.D
                    If i = 255 And j <> m_intIPCountC Then
                    Else
                        m_idqNetwork.D = i
                        If v_ipaPingList(v_ipaPingList.Length - 2) IsNot v_ipaPingList(v_ipaPingList.Length - 1) Then
                            v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                            ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                        Else
                            ReDim Preserve v_ipaPingList(v_ipaPingList.Length - 3)
                        End If
                    End If
                End While
                i = 0
                j += 1
            End While

            'Small
            i = 0

        Else
            While i < (m_intIPCount)
                ReDim Preserve v_ipaPingList(v_ipaPingList.Length)
                i += 1
                v_ipaPingList(v_ipaPingList.Length - 1) = idq2ipa(m_idqNetwork)
                m_idqNetwork.D = m_idqNetwork.D + 1
            End While
        End If

        Return (v_ipaPingList)


    End Function

    Private Function idq2ipa(ByVal v_idqIP As IPDottedQuad)
        Dim m_ipaIP As IPAddress
        m_ipaIP = IPAddress.Parse(v_idqIP.A & "." & v_idqIP.B & "." & v_idqIP.C & "." & v_idqIP.D)
        Return (m_ipaIP)
    End Function

    Private Function GetNetworkAddress(ByVal v_intCIDR As Integer, ByVal v_strMyIP As String)
        v_idqIP = CIdq(v_strMyIP)
        Dim m_idqNetwork As New IPDottedQuad
        Dim m_intMask As Integer

        If v_intCIDR >= 8 Then
            m_idqNetwork.A = v_idqIP.A

            If v_intCIDR < 16 Then
                m_intMask = v_intCIDR - 8
                m_strNetAddress = bin2dec(BinStringAND(dec2bin(v_idqIP.D), dec2mask(m_intMask)))
                m_idqNetwork.B = m_strNetAddress
                m_idqNetwork.C = 0
                m_idqNetwork.D = 0
            End If

        ElseIf v_intCIDR >= 16 Then
            m_idqNetwork.B = v_idqIP.B

            If v_intCIDR < 24 Then
                m_intMask = v_intCIDR - 16
                m_strNetAddress = bin2dec(BinStringAND(dec2bin(v_idqIP.D), dec2mask(m_intMask)))
                m_idqNetwork.C = m_strNetAddress
                m_idqNetwork.D = 0
            End If

        ElseIf v_intCIDR >= 24 Then
            m_idqNetwork.C = v_idqIP.C

            m_intMask = v_intCIDR - 24
            m_strNetAddress = bin2dec(BinStringAND(dec2bin(v_idqIP.D), dec2mask(m_intMask)))
            m_idqNetwork.D = m_strNetAddress
        End If

        Return (m_idqNetwork)
    End Function

    Private Function dec2bin(ByVal v_intDec As Integer)
        Dim m_strBin As String = ""
        For i = 8 To 0 Step -1
            If v_intDec And (2 ^ i) Then
                m_strBin = m_strBin + "1"
            Else
                m_strBin = m_strBin + "0"
            End If
        Next
        Return (m_strBin)
    End Function

    Private Function dec2mask(ByVal v_intDec As Integer)
        Dim m_strBin As String = ""
        For i = 0 To 8 Step 1
            If v_intDec > i Then
                m_strBin = m_strBin + "1"
            Else
                m_strBin = m_strBin + "0"
            End If
        Next
        Return (m_strBin)
    End Function

    Private Function bin2dec(ByVal v_strBin As String)
        Dim m_intInt As Integer = 0
        For i = 8 To 0 Step -1
            If v_strBin.Chars(i) = "1" Then
                m_intInt = m_intInt + (2 ^ i)
            End If
        Next
        Return (m_intInt)
    End Function

    Private Function BinStringAND(ByVal v_strBin1, ByVal v_strBin2)
        Dim m_strBin As String = ""
        For i = 8 To 0 Step -1
            If v_strBin1.Chars(i) And v_strBin2.Chars(i) Then
                m_strBin = m_strBin + "1"
            Else
                m_strBin = m_strBin + "0"
            End If
        Next
        Return (m_strBin)
    End Function

    Private Function SendPing(ByVal v_ipaIP As IPAddress, ByVal v_intTimoutValue As Integer)
        Dim v_blnStatus As Boolean
        Dim m_ping As New Ping
        Dim m_idqIPTmp As New IPDottedQuad

        Dim m_strIPTmp = v_ipaIP.ToString
        m_idqIPTmp = CIdq(m_strIPTmp)
        If m_idqIPTmp.D <> 0 Then
            Dim m_pingreply As PingReply = m_ping.Send(v_ipaIP, v_intTimoutValue)
            If m_pingreply.Status = IPStatus.Success Then
                v_blnStatus = True
            Else
                v_blnStatus = False
            End If
            Return (v_blnStatus)
        Else
            v_blnStatus = False
            Return (v_blnStatus)
        End If
    End Function

    Private Sub CheckStatus()
        Dim blnNetworkStatus As Boolean
        If My.Computer.Network.IsAvailable = True Then
            blnNetworkStatus = True
        Else
            blnNetworkStatus = False
        End If
    End Sub

    Private Sub loadMyIPs()
        Me.cmbMyIP.DropDownStyle = ComboBoxStyle.DropDownList
        Dim ipaMyIPs As IPAddress() = Dns.GetHostAddresses(Dns.GetHostName())
        Dim index As Integer = 0
        Dim tmpIndex As Integer = 0
        For Each ip In ipaMyIPs
            ipstring = ip.ToString
            Debug.WriteLine(ip)
            If ipstring.IndexOf(".") >= 0 Then
                tmpIndex += 1
                Me.cmbMyIP.Items.Insert((tmpIndex), ip)
            End If
            index += 1
        Next ip
        cmbMyIP.SelectedIndex = 1
    End Sub

    Private Sub SaveFile(ByRef FileName As String)

        Dim NetworkIP As IPAddress

        Using sw As StreamWriter = New StreamWriter(FileName)

            ' Add header to file
            sw.WriteLine("'A Simple Network Mapper")
            sw.Write("'The timestamp is: ")
            sw.WriteLine(DateTime.Now)
            'Change this to handle CIDR, use if? Class/CIDR
            NetworkIP = IPAddress.Parse(ipqMySubNet.A & "." & ipqMySubNet.B & "." & ipqMySubNet.C & "." & "0")
            sw.Write("'Connected IPs in the subnet ")
            sw.Write(NetworkIP)
            sw.Write("/")
            sw.Write(intCIDR)
            sw.WriteLine(":")

            Dim index = 0
            'If nothing found, say so
            If lstActive.Items(index) Is Nothing Then
                sw.WriteLine("No Active IPs found")

            ElseIf lstActive.Items(index) IsNot Nothing Then
                'Else write the file out
                For Each item As String In lstActive.Items
                    sw.WriteLine(item)
                Next
            End If

            sw.Close()
        End Using
        '
    End Sub

    Public Function CIdq(ByVal v_strIP)
        'Convert strIP to ipqIP
        Dim index As Integer = 0
        Dim v_ipqIP As New IPDottedQuad
        Dim strTemp As String() = v_strIP.Split(New Char() {"."c})
        For Each part In strTemp
            strTemp(index) = part
            index += 1
        Next
        v_ipqIP.A = strTemp(0)
        v_ipqIP.B = strTemp(1)
        v_ipqIP.C = strTemp(2)
        v_ipqIP.D = strTemp(3)
        Return (v_ipqIP)
    End Function

    Private Sub chkExitAfterSave_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles chkExitAfterSave.CheckedChanged
        If chkExitAfterSave.Checked Then
            blnExitAfterSave = True
            My.Settings.ExitAfterSave = True
        Else
            blnExitAfterSave = False
            My.Settings.ExitAfterSave = False
        End If
    End Sub

    Private Sub chkAutoSaveToLast_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles chkAutoSaveToLast.CheckedChanged
        If chkAutoSaveToLast.Checked = True Then
            blnAutoSaveToLast = True
            My.Settings.AutoSave = True
        Else
            blnAutoSaveToLast = False
            My.Settings.AutoSave = False
        End If
    End Sub

    'Classes
    Public Class IPDottedQuad
        'Class to hold each member of an IP
        'Denotes an IP in the form A.B.C.D
        'Debug.WriteLine("")
        Private intA As Integer
        Private intB As Integer
        Private intC As Integer
        Private intD As Integer

        'Constructor
        Public Sub New()
            intA = 0
            intB = 0
            intC = 0
            intD = 0
        End Sub

        'Finalizer
        Protected Overrides Sub Finalize()
            'Not needed?
        End Sub

        'Conversions


        'Set/Get
        Public Property A() As Integer
            Get
                Return intA
            End Get
            Set(ByVal value As Integer)
                If value >= 0 And value <= 255 Then
                    intA = value
                Else
                    intA = 1
                    MessageBox.Show("Object of Class MySubNet.A Out of bounds (1-254)", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End If
            End Set
        End Property

        Public Property B() As Integer
            Get
                Return intB
            End Get
            Set(ByVal value As Integer)
                If value >= 0 And value <= 255 Then
                    intB = value
                Else
                    intB = 0
                    MessageBox.Show("Object of Class MySubNet.B Out of bounds (0-254)", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End If
            End Set
        End Property

        Public Property C() As Integer
            Get
                Return intC
            End Get
            Set(ByVal value As Integer)
                If value >= 0 And value <= 255 Then
                    intC = value
                Else
                    intC = 1
                    MessageBox.Show("Object of Class MySubNet.C Out of bounds (1-254)", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End If
            End Set
        End Property

        Public Property D() As Integer
            Get
                Return intD
            End Get
            Set(ByVal value As Integer)
                If value >= 0 And value <= 255 Then
                    intD = value
                Else
                    intD = 1
                    MessageBox.Show("Object of Class MySubNet.D Out of bounds (1-254)", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End If
            End Set
        End Property
    End Class

End Class